package com.ljx.orm.util;

import com.ljx.annotation.TableFiled;
import com.ljx.annotation.TableId;
import com.ljx.annotation.TableName;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author LJX
 * @Description: TODO
 * @Date: 2022/10/28 14:24
 * @Version 1.0
 */
public class BaseDao<T> {
	/**
	 * 	声明一个实体类的反射对象
 	 */
	private Class<?> aClass;

	public BaseDao(){
		// this既可以表示当前类对象，又可以表示继承类对象
		// 获取继承类（子类）的反射类对象
		Class<? extends BaseDao> aClazz = this.getClass();
		// 获取BaseDao的反射类对象
		ParameterizedType genericSuperclass = (ParameterizedType)aClazz.getGenericSuperclass();
		// 获取所有泛型类的反射类
		Type[] types = genericSuperclass.getActualTypeArguments();
		Type type = types[0];
		aClass= (Class<?>) type;
	}

	public int insert(T t)throws Exception{
		StringBuilder sql = new StringBuilder("insert into ");
		// 根据对象获取该对象的反射类Class
		Class<?> aClass = t.getClass();
		// 获取反射类上的注解对象
		TableName annotation = aClass.getAnnotation(TableName.class);
		// 标明对象
		String tableName="";
		if(annotation!=null){
			tableName=annotation.value();
		}else {
			// 获取实体类名
			tableName=aClass.getSimpleName();
		}
		sql.append(tableName);
		// 获取所有的列名
		Field[] fields = aClass.getDeclaredFields();
		// 声明一个集合表示所有的列名
		List<String> columns = new ArrayList<>();
		// 再声明一个集合表示该类所对应的值
		ArrayList<Object> values = new ArrayList<>();
		for (Field field : fields) {
			// 获取属性对象上的注解对象
			TableId tableId = field.getAnnotation(TableId.class);
			TableFiled tableFiled = field.getAnnotation(TableFiled.class);
			// 声明一个列名或者列值的临时临时存储数据的变量
			String name="";
			if(tableId!=null){
				continue;
			}
			if(tableFiled!=null){
				name=tableFiled.name();
			}else {
				name=field.getName();
			}
			// 获取对象t 对应的列值
			field.setAccessible(true);
			Object o = field.get(t);
			values.add("'"+o+"'");
			columns.add(name);

		}

		String columnNames = columns.toString().replace("[", "(").replace("]", ")");
		String valueNames = values.toString().replace("[", "(").replace("]", ")");
		sql.append(columnNames);
		sql.append("values");
		sql.append(valueNames);
		System.out.println(sql);
		// 执行sql
		Connection connection = DBUtil.getConnection();
		PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
		int row = preparedStatement.executeUpdate();


		return row;
	}

	public int update(T t)throws Exception{
		StringBuilder sql = new StringBuilder("update ");
		// 根据对象获取该对象的反射类Class
		Class<?> aClass = t.getClass();
		// 获取反射类上的注解对象
		TableName annotation = aClass.getAnnotation(TableName.class);
		// 标明对象
		String tableName="";
		if(annotation!=null){
			tableName=annotation.value();
		}else {
			// 获取实体类名
			tableName=aClass.getSimpleName();
		}
		sql.append(tableName);
		sql.append(" set ");

		// 获取所有的列名
		Field[] fields = aClass.getDeclaredFields();
		// 获取主键的名字和主键的值
		String idname="";
		int idValue=0;
		boolean flag=false;
		for (Field field : fields) {
			// 获取属性对象上的注解对象
			TableId tableId = field.getAnnotation(TableId.class);
			TableFiled tableFiled = field.getAnnotation(TableFiled.class);
			// 声明一个列名或者列值的临时临时存储数据的变量
			String name="";
			if(tableId!=null){
				// 获取主键Id的值
				idname=tableId.name();
				field.setAccessible(true);
				Object o1 = field.get(t);
				idValue= (int) o1;
				flag=true;
				continue;
			}
			if(tableFiled!=null){
				name=tableFiled.name();
			}else {
				name=field.getName();
			}
			// 添加到sql语句中取
			sql.append(name+" = ");
			// 获取对象t 对应的列值
			field.setAccessible(true);
			Object o = field.get(t);
			sql.append("'"+o+"',");


		}
		if(flag!=true){
			throw new RuntimeException("请为其设置主键注解");
		}
		sql.delete(sql.length()-1,sql.length());
		sql.append(" where ");
		sql.append(idname);
		sql.append(" = ");
		sql.append(idValue);
		System.out.println(sql);
		// 执行sql
		Connection connection = DBUtil.getConnection();
		PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
		int row = preparedStatement.executeUpdate();
		return row;
	}


	public int delete(Object id)throws  Exception{

		StringBuffer sql = new StringBuffer("delete from ");
		TableName annotation = aClass.getAnnotation(TableName.class);
		// 获取表名
		String tableName="";
		if(annotation!=null) {
			//获取注解的属性
			tableName = annotation.value();
		}else{
			//获取实体名(通过反射类获取该实体类的类名)
			tableName = aClass.getSimpleName();
		}
		sql.append(tableName+" where ");
		// 获取所有属性对象
		Field[] fields = aClass.getDeclaredFields();
		boolean flag=false;
		for (Field field : fields) {
			TableId tableId = field.getAnnotation(TableId.class);
			if (tableId!=null){
				sql.append(tableId.name()+" ='"+id+"'");
				flag=true;
				break;
			}

		}
		if(flag==false){
			throw new RuntimeException("没有主键注解");
		}
		System.out.println(sql);
		//执行sql
		Connection connection = DBUtil.getConnection();
		PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
		int row = preparedStatement.executeUpdate();
		return row;

	}

	public T findOneTable(Object id)throws  Exception{
		StringBuffer sql = new StringBuffer("select * from ");
		TableName annotation = aClass.getAnnotation(TableName.class);
		//获取表名
		String tableName="";
		if(annotation!=null){
			tableName=annotation.value();
		}else{
			tableName = aClass.getSimpleName();
		}
		sql.append(tableName+" where ");
		//获取所有的属性对象
		Field[] declaredFields = aClass.getDeclaredFields();
		boolean flag=false;
		for (Field field : declaredFields) {
			TableId tableId = field.getAnnotation(TableId.class);
			if(tableId!=null){
				sql.append(tableId.name()+" = '"+id+"'");
				flag=true;
				break;
			}
		}
		if(flag==false){
			throw new RuntimeException("没有主键注解");
		}

		//执行sql。
		Connection connection=DBUtil.getConnection();
		PreparedStatement preparedStatement=connection.prepareStatement(sql.toString());
		ResultSet resultSet = preparedStatement.executeQuery();
		// 如果没有查询的结果则赋值为空
		T t=null;
		// 把查询到的结果赋值给t 对象
		while (resultSet.next()){
			t = (T) aClass.newInstance();
			for (Field field : declaredFields) {
				field.setAccessible(true);
				TableFiled tableFiled = field.getAnnotation(TableFiled.class);
				TableId tableId = field.getAnnotation(TableId.class);
				if(tableId!=null){
					field.set(t,resultSet.getObject(tableId.name()));
					continue;
				}
				if(tableFiled==null){
					Object object = resultSet.getObject(field.getName());
					field.set(t,checkObject(object));
				}else{
					Object object = resultSet.getObject(tableFiled.name());
					field.set(t,checkObject(object));
				}
			}
		}
		return t;
	}

	public List<T> findAll()throws  Exception{
		StringBuffer sql = new StringBuffer("select * from ");
		TableName annotation = aClass.getAnnotation(TableName.class);
		//获取表名
		String tableName="";
		if(annotation!=null){
			tableName=annotation.value();
		}else{
			tableName = aClass.getSimpleName();
		}
		sql.append(tableName);
		//获取所有的属性对象
		Field[] declaredFields = aClass.getDeclaredFields();
		//执行sql。
		Connection connection=DBUtil.getConnection();
		PreparedStatement preparedStatement=connection.prepareStatement(sql.toString());
		ResultSet resultSet = preparedStatement.executeQuery();
		// 如果没有查询的结果则赋值为空
		T t=null;
		// 把查询到的结果赋值给t 对象
		List<T> arrayList = new ArrayList<>();
		while (resultSet.next()){
			t = (T) aClass.newInstance();
			for (Field field : declaredFields) {
				field.setAccessible(true);
				TableFiled tableFiled = field.getAnnotation(TableFiled.class);
				TableId tableId = field.getAnnotation(TableId.class);
				if(tableId!=null){
					field.set(t,resultSet.getObject(tableId.name()));
					continue;
				}
				if(tableFiled==null){
					Object object = resultSet.getObject(field.getName());
					field.set(t,checkObject(object));
				}else{
					Object object = resultSet.getObject(tableFiled.name());
					field.set(t,checkObject(object));
				}
			}
			arrayList.add(t);
		}
		return arrayList;
	}

	//判断某个类型是否为时间类型
	public Object checkObject(Object o){
		//如果数据库中的类型为dateTime对应java中LocalDateTime
		//数据库中Date类型对应java中Date
		if(o instanceof LocalDateTime){
			LocalDateTime date= (LocalDateTime) o;
			DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
			String format = date.format(dateTimeFormatter);
			return format;
		}
		return o;
	}
	//查询所有记录.


}
